package Kalah;

public class GameState {
	static final int HOLES_PER_PLAYER = 6; 
	static final int INIT_BEANS_PER_HOLE = 6;
	static final int INIT_BEANS_AT_POT = 0;
	static final int EMPTY_HOLE = 0;
	static final int POT = 0;
	static final int NULL = -9999;

	static final boolean ADD_1 = true;
	static final boolean SUB_1 = false;
	static final boolean TOP_PLAYER = true;
	
	BeanKeeper m_bk;
	//private int[] m_holesTopPlayer; // holds information of how many beans are in each pot
	//private int[] m_holesBotPlayer; // holds information of how many beans are in each pot
	private boolean m_currentPlayer;
	private boolean m_gameOver;
	
	private class BeanKeeper{
		private int[] m_holesTopPlayer; // holds information of how many beans are in each pot
		private int[] m_holesBotPlayer; // holds information of how many beans are in each pot
		public BeanKeeper(){
			m_holesTopPlayer = new int[HOLES_PER_PLAYER];
			m_holesBotPlayer = new int[HOLES_PER_PLAYER];
			for(int i : m_holesTopPlayer){
				// skip index 0, this will be the POT
				if(i != POT){
					m_holesTopPlayer[i] = INIT_BEANS_PER_HOLE;
					m_holesBotPlayer[i] = INIT_BEANS_PER_HOLE;
				}
				else{
					m_holesTopPlayer[i]	= INIT_BEANS_AT_POT;
					m_holesBotPlayer[i]	= INIT_BEANS_AT_POT;
				}
			}
			
		}
		public BeanKeeper(BeanKeeper bk){
			m_holesTopPlayer = bk.m_holesTopPlayer;
			m_holesBotPlayer = bk.m_holesBotPlayer;
		}
		
		public int[] getArray(boolean isTop){
			return isTop ?
				m_holesTopPlayer:
				m_holesBotPlayer;
		}
		public void setArray(boolean isTop, int[] array){
			if(isTop)
				m_holesTopPlayer = array;
			else
				m_holesBotPlayer = array;
		}
		public int getBeanCount(Position pos){
			return getBeanCount(pos.isTopPosition(),pos.getHoleNumber());
		}
		public int getBeanCount(boolean isTop, int whichHole){
			if(isTop){
				return m_holesTopPlayer[whichHole];
			}
			else{
				return m_holesBotPlayer[whichHole];
			}
		}
		public void setBeanCount(boolean isTop, int whichHole, int value){
			if(isTop)
				m_holesTopPlayer[whichHole] = value;
			else
				m_holesBotPlayer[whichHole] = value;
		}
		public void setBeanCount(boolean isTop, int whichHole, boolean addOrSubtract){
			if(isTop){
				m_holesTopPlayer[whichHole] = 
					addOrSubtract?
							m_holesTopPlayer[whichHole]++:
							m_holesTopPlayer[whichHole]--;
			}
			else{
				m_holesBotPlayer[whichHole] = 
					addOrSubtract?
							m_holesBotPlayer[whichHole]++:
							m_holesBotPlayer[whichHole]--;
			}
		}
		public void setBeanCount(Position pos, int value){
			if(pos.isTopPosition())
				m_holesTopPlayer[pos.getHoleNumber()] = value;
			else
				m_holesBotPlayer[pos.getHoleNumber()] = value;
		}
		public void setBeanCount(Position pos, boolean addOrSubtract){
			if(pos.isTopPosition()){
				m_holesTopPlayer[pos.getHoleNumber()] = 
					addOrSubtract?
							m_holesTopPlayer[pos.getHoleNumber()]++:
							m_holesTopPlayer[pos.getHoleNumber()]--;
			}
			else{
				m_holesBotPlayer[pos.getHoleNumber()] = 
					addOrSubtract?
							m_holesBotPlayer[pos.getHoleNumber()]++:
							m_holesBotPlayer[pos.getHoleNumber()]--;
			}
		}
	}
	public Position createPosition(boolean isTop, int whichHole){
		return new Position(isTop,whichHole);
	}

	
	public int getBeanCount(boolean isTop, int whichHole){
		return m_bk.getBeanCount(isTop, whichHole);
	}
	public int getBeanCount(Position pos){
		return m_bk.getBeanCount(pos);
	}
	public boolean checkIfPlayerHasNoPlayableMoves(boolean isTop){
		int[] thisArray = m_bk.getArray(isTop);
		for(int i = 1; i < thisArray.length; ++i){
			if(thisArray[i] > 0){
				gameOverBeanCleanUp(!isTop);
				return true;
			}
		}
		return false;
	}
	
	// gets all the beans from each player and puts it onto their pot. 
	// checkIfPlayerHasNoPlayableMoves has to be true in order to continue here
	private void gameOverBeanCleanUp(boolean oppositePlayerIsTop){
		int[] thisArray = m_bk.getArray(oppositePlayerIsTop);
		for(int i = 1; i < thisArray.length; ++i){
			int beanCount = thisArray[i];
			thisArray[POT] += beanCount;
			thisArray[i] = EMPTY_HOLE;
		}
		m_bk.setArray(oppositePlayerIsTop, thisArray);
		m_gameOver = true;
	}
	
	
	public void init(){
		m_currentPlayer = TOP_PLAYER;
		m_gameOver = false;
		m_bk = new BeanKeeper();
	}
	public GameState(){
		init();
	}
	public boolean getCurrentPlayer(){
		return m_currentPlayer;
	}
	public GameState(GameState game){
		m_currentPlayer = game.m_currentPlayer;
		m_gameOver = game.m_gameOver;
		m_bk = new BeanKeeper(game.m_bk);
	}
	public boolean checkValidMove(boolean isTop, int a_holeNumber){
		
		return
			// checks if hole number is correct
			(a_holeNumber > POT && a_holeNumber < HOLES_PER_PLAYER) &&
			// checks if hole is not empty
			m_bk.getBeanCount(isTop, a_holeNumber) > EMPTY_HOLE;
		
	}
	public void applyMove(Position pos) throws InvalidMoveException{
		if(!checkValidMove(pos.isTopPosition(), pos.getHoleNumber())) 
			throw new InvalidMoveException("Move is not valid.");
		else{
			// hand out beads from that position
			int beansToGive = m_bk.getBeanCount(pos);
			boolean currentlyAtTop = pos.isTopPosition();
			// set chosen hole as empty
			m_bk.setBeanCount(pos, EMPTY_HOLE);
			int currentHole = NULL;
			while(beansToGive > 0){
				if(currentHole < 0){
					currentHole = HOLES_PER_PLAYER - 1; 
					currentlyAtTop = !currentlyAtTop;
				}
				m_bk.setBeanCount(currentlyAtTop, currentHole, ADD_1);
				beansToGive--;
			}
		}
	}
	public void applyMove(boolean isTopPlayer, int a_holeNumber) throws InvalidMoveException{
		if(!checkValidMove(isTopPlayer, a_holeNumber)) 
			throw new InvalidMoveException("Move is not valid.");
		else{
			// hand out beads from that position
			int beansToGive = m_bk.getBeanCount(isTopPlayer, a_holeNumber);
			// set chosen hole as empty
			m_bk.setBeanCount(isTopPlayer, a_holeNumber, EMPTY_HOLE);			

			// hand beans out counter clockwise
			int currentHole = NULL;
			boolean currentlyAtTop = isTopPlayer;
			currentHole = a_holeNumber - 1;
				
			while(beansToGive > 0){
				if(currentHole < 0){
					currentHole = HOLES_PER_PLAYER - 1; 
					currentlyAtTop = !currentlyAtTop;
				}
				m_bk.setBeanCount(currentlyAtTop, currentHole, ADD_1);
				beansToGive--;
			}
			checkIfPlayerHasNoPlayableMoves(isTopPlayer);
			
		}
	}
	
	public Object clone(){
		return new GameState(this);
	}
}

